/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Model;

import Model.Piece.TypePiece;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author proprietaire
 */
public class Jeu extends Observable implements Runnable {

    private Grille grille;
    private Piece pieceCourante;
    private Piece pieceSuivante;
    private boolean gameOver;
    private int level = 400;
    private int score = 0;
    private boolean swap = false;

    public Jeu() {
        grille = new Grille(20, 10);
        gameOver = false;
    }

    public boolean getGameOver() {
        return gameOver;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }

    public Grille getGrille() {
        return grille;
    }

    public Piece getPieceCourante() {
        return pieceCourante;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    synchronized public void placerPieceDansGrille() {

        Case[][] matrice = grille.getMatrice();
        Case[][] tab = pieceCourante.getTabPiece();
        int offset_x = pieceCourante.getOffset_i();
        int offset_y = pieceCourante.getOffset_j();


        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                Case temp = tab[i][j];
                if (temp.getOccupe()) {
                    int ir = i + offset_x;
                    int jr = j + offset_y;

                    if (0 <= ir && ir < matrice.length && 0 <= jr && jr < matrice[0].length) {

                        grille.setMatrice(ir, jr, tab[i][j]);

                    }
                }
            }
        }
        setChanged();
        notifyObservers();
    }

    synchronized public void effacerPieceDansGrille() {

        Case[][] matrice = grille.getMatrice();
        Case[][] tab = pieceCourante.getTabPiece();
        int offset_x = pieceCourante.getOffset_i();
        int offset_y = pieceCourante.getOffset_j();


        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                Case temp = tab[i][j];
                if (temp.getOccupe()) {
                    int ir = i + offset_x;
                    int jr = j + offset_y;

                    if (0 <= ir && ir < matrice.length && 0 <= jr && jr < matrice[0].length) {
                        grille.getMatrice()[ir][jr].clear();
                    }
                }
            }
        }
        setChanged();
        notifyObservers();
    }

    synchronized public boolean rotationGauche() {
        boolean rep = true;
        effacerPieceDansGrille();
        pieceCourante.setRotation(pieceCourante.getRotation() - 1);
        if (collision()) {
            pieceCourante.setRotation(pieceCourante.getRotation() + 1);
            rep = false;
        }
        placerPieceDansGrille();
        return rep;
    }

    synchronized public boolean translationBas() {
        boolean rep = true;
        effacerPieceDansGrille();
        pieceCourante.setOffset_i(pieceCourante.getOffset_i() + 1);
        if (collision()) {
            pieceCourante.setOffset_i(pieceCourante.getOffset_i() - 1);
            rep = false;
        }
        placerPieceDansGrille();
        return rep;
    }

    synchronized public boolean translationDroite() {
        boolean rep = true;
        effacerPieceDansGrille();
        pieceCourante.setOffset_j(pieceCourante.getOffset_j() + 1);
        if (collision()) {
            pieceCourante.setOffset_j(pieceCourante.getOffset_j() - 1);
            rep = false;
        }
        placerPieceDansGrille();
        return rep;
    }

    synchronized public boolean translationGauche() {
        boolean rep = true;
        effacerPieceDansGrille();
        pieceCourante.setOffset_j(pieceCourante.getOffset_j() - 1);
        if (collision()) {
            pieceCourante.setOffset_j(pieceCourante.getOffset_j() + 1);
            rep = false;
        }
        placerPieceDansGrille();
        return rep;
    }

    public boolean collision() {
        Case[][] matrice = grille.getMatrice();
        Case[][] tab = pieceCourante.getTabPiece();
        int offset_x = pieceCourante.getOffset_i();
        int offset_y = pieceCourante.getOffset_j();
        boolean rep = false;

        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                Case temp = tab[i][j];
                if (temp.getOccupe()) {
                    int ir = i + offset_x;
                    int jr = j + offset_y;

                    if (0 <= ir && ir < matrice.length && 0 <= jr && jr < matrice[0].length) {
                        if (matrice[ir][jr].getOccupe()) {
                            rep = true;
                        }
                    } else {
                        rep = true;
                    }
                }
            }
        }
        return rep;
    }

    public ArrayList<Integer> detecterLigne() {
        ArrayList<Integer> list = new ArrayList<>();
        Case[][] matrice = grille.getMatrice();

        for (int i = matrice.length - 1; i >= 0; i--) {
            boolean ligne = true;
            for (int j = 0; j < matrice[0].length; j++) {
                if (!matrice[i][j].getOccupe()) {
                    ligne = false;
                }

            }
            if (ligne) {
                list.add(i);
                score++;
                continue;
            }

        }
        return list;
    }

    synchronized public void effacerLigne() {
        ArrayList<Integer> list = detecterLigne();
        Case[][] matrice = grille.getMatrice();

        for (int i = list.size() - 1; i >= 0; i--) {
            for (int offsetX = list.get(i); offsetX >= 0; offsetX--) {
                for (int j = 0; j < 10; j++) {
                    if (offsetX - 1 >= 0) {
                        matrice[offsetX][j].setCouleur(matrice[offsetX - 1][j].getColor());
                        matrice[offsetX][j].setOccupe(matrice[offsetX - 1][j].getOccupe());
                    }
                }

            }
        }
        setChanged();
        notifyObservers();
    }

    public void setPieceCourante(Piece pieceCourante) {
        this.pieceCourante = pieceCourante;
    }

    public void setPieceSuivante(Piece pieceSuivante) {
        this.pieceSuivante = pieceSuivante;
    }

    synchronized public boolean isGameOver(int offset_x) {
        if (pieceCourante.getOffset_i() == offset_x) {
            return true;
        }
        return false;
    }

    public void descenteToutbas() {
        if (swap) {
            pieceSuivante.setOffset_i(-1);
            pieceSuivante.setOffset_j(3);
            swap = false;
        }
        while (translationBas());
        pieceCourante = pieceSuivante;
        pieceSuivante = getRandomPiece();
        effacerLigne();
    }

    synchronized public void afficherGrille() {
        for (int i = 0; i < 20; i++) {
            System.out.println();
            for (int j = 0; j < 10; j++) {
                if (grille.getMatrice()[i][j].getOccupe()) {
                    System.out.print(1);
                } else {
                    System.out.print(0);
                }
            }
        }
        System.out.println("");
    }

    //retourne 1 tant que la pièce peut tomber et -1 si c'est fini
    //Fonction pour les tests de la classe jeu (appelé dans le run en dessous);
    public Piece getRandomPiece() {
        Random r = new Random();
        Piece tmp = null;
        int rand = r.nextInt(7);
        if (rand == 0) {
            tmp = new Piece(TypePiece.O);
        }
        if (rand == 1) {
            tmp = new Piece(TypePiece.I);
        }
        if (rand == 2) {
            tmp = new Piece(TypePiece.T);
        }
        if (rand == 3) {
            tmp = new Piece(TypePiece.Z);
        }
        if (rand == 4) {
            tmp = new Piece(TypePiece.S);
        }
        if (rand == 5) {
            tmp = new Piece(TypePiece.L);
        }
        if (rand == 6) {
            tmp = new Piece(TypePiece.J);
        }

        return tmp;
    }

    public Piece getPieceSuivante() {
        return pieceSuivante;
    }

    synchronized public void swap() {

        swap = true;
        effacerPieceDansGrille();
        Piece tmpP = pieceCourante;

        pieceCourante = pieceSuivante;
        pieceCourante.setOffset_i(tmpP.getOffset_i());
        pieceCourante.setOffset_j(tmpP.getOffset_j());

        tmpP.setOffset_i(pieceCourante.getOffset_i());
        tmpP.setOffset_j(pieceCourante.getOffset_j());
        pieceSuivante = tmpP;

        if (collision()) {
            tmpP = pieceCourante;

            pieceCourante = pieceSuivante;
            pieceCourante.setOffset_i(tmpP.getOffset_i());
            pieceCourante.setOffset_j(tmpP.getOffset_j());


            tmpP.setOffset_i(pieceCourante.getOffset_i());
            tmpP.setOffset_j(pieceCourante.getOffset_j());
            pieceSuivante = tmpP;

        }
        placerPieceDansGrille();
    }

    @Override
    public void run() {


        /*s'éxécute dans le Thread t de tetris*/
        pieceCourante = getRandomPiece();
        pieceSuivante = getRandomPiece();
        placerPieceDansGrille();
        boolean boucle = true;
        boolean gameOver = false;

        while (boucle) {

            if (swap) {
                pieceSuivante.setOffset_i(-1);
                pieceSuivante.setOffset_j(3);
                swap = false;
            }

            if (!translationBas()) {
                effacerLigne();
                int ancienOffset_x = pieceCourante.getOffset_i();
                pieceCourante = pieceSuivante;

                gameOver = isGameOver(ancienOffset_x);
                if (gameOver) {
                    this.gameOver = true;
                }
                pieceSuivante = getRandomPiece();
                placerPieceDansGrille();



            }
            try {
                Thread.sleep(level);
            } catch (InterruptedException ex) {
                Logger.getLogger(Jeu.class.getName()).log(Level.SEVERE, null, ex);
            }

        }



    }
}

/*
 * Faire que la piece commence tout en haut et s'arrete en bas (le problème est qu'on a un tableau de Case[4][4]
 * Il faut travailler sur la fonction placerPieceDansGrille() et translationBas(pas sur) 
 * Il faudrait vérifier avant chaque déplacement que celui ci est possible faire une fonction boolean deplacementPossible()
 * 
 * 
 
 
 */
